import base64
import socket
import sys
from utils import (
    print_to_client, print_to_server, parse_response, send_msg, commands, send_mail, read_all_mail, load_config,
    generate_hmac_value,

)


PERSONAL_ID = 'C8BB1A'
PERSONAL_SECRET = '4acb39586b46d8455b20ebfce57b46cd'


class Client:
    def __init__(self, path):
        self.server_port = None
        try:
            config = load_config(path)
            send_box = config['DEFAULT']['send_path']
            self.server_port = config['DEFAULT']['server_port']
            # self.server_port = config['DEFAULT']['spy_port']
        except Exception as e:
            exit(2)
        self.auth = False
        self.mails,self.auth = read_all_mail(send_box)
        self.host = '127.0.0.1'
        self.name = PERSONAL_ID
        self.secret = PERSONAL_SECRET
        self.sending_all_mails()
        # self.send_my_input()
    def sending_all_mails(self):
        for mail in self.mails:
            self.send_mail(mail)

    def send_mail(self, mail):
        with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as client:
            if mail[5]:
                print_to_client(f"{mail[6]}: Bad formation")
                exit(0)
            try:
                client.connect((self.host, int(self.server_port)))
            except Exception:
                print_to_client("Cannot establish connection")
                exit(3)
            data = {'sender': mail[0], 'receiver': mail[1], 'date': mail[2],
                    "subject": mail[3],
                    'content': mail[4]
                    }
            already_sent = {'sender': 0, 'receiver': 0, 'data': 0, 'date': 0, "subject": 0, 'content': 0}
            while True:
                try:
                    response = client.recv(1024).decode()
                except:
                    print_to_client(f"Lost connection")
                code, parameter = parse_response(response)
                print_to_server(response)
                if code == '220':
                    send_msg(client, f"{commands.EHLO.value} {self.host}")
                    print_to_client(f"{commands.EHLO.value} {self.host}")
                elif code == '250':
                    # 如果auth 为false的话，表示不需要验证直接发邮件，
                    if self.auth:
                        if parameter == 'AUTH CRAM-MD5' or parameter == '127.0.0.1':
                            send_msg(client, "AUTH CRAM-MD5")
                            print_to_client(f"AUTH CRAM-MD5")
                        elif parameter == 'Requested mail action okay completed':
                            if already_sent['receiver'] == 1 and already_sent['date'] == 0:
                                print_to_client(commands.DATA.value)
                                send_msg(client, commands.DATA.value)
                                continue
                            elif already_sent['content'] == 1:
                                print_to_client(commands.QUIT.value)
                                send_msg(client, commands.QUIT.value)
                                data.clear()
                                already_sent.clear()
                                continue
                            already_sent = send_mail(data, already_sent, client)
                    else:
                        if parameter.endswith('AUTH CRAM-MD5') or parameter == '127.0.0.1':
                            send_msg(client, f"{commands.MAIL.value} FROM:{data['sender']}")
                            print_to_client(f"{commands.MAIL.value} FROM:{data['sender']}")
                            already_sent['sender'] = 1
                        # elif parameter == self.host:
                        #     continue
                        elif parameter == 'Requested mail action okay completed':
                            if already_sent['receiver'] == 1 and already_sent['date'] == 0:
                                send_msg(client, commands.DATA.value)
                                print_to_client(commands.DATA.value)
                                continue
                            elif already_sent['content'] == 1:
                                send_msg(client, commands.QUIT.value)
                                print_to_client(commands.QUIT.value)
                                data.clear()
                                already_sent.clear()
                                continue
                            already_sent = send_mail(data, already_sent, client)
                elif code == '354':
                    if already_sent['content'] == 1:
                        send_msg(client, ".")
                        print_to_client(".")
                    send_mail(data, already_sent, client)
                elif code == '221':
                    client.close()
                    break
                elif code == '334':
                    ans = generate_hmac_value(PERSONAL_SECRET,base64.b64decode(parameter))
                    ans = self.name + " " + ans
                    send_msg(client,f"{base64.b64encode(ans.encode('ascii')).decode()}")
                    print_to_client(f"{base64.b64encode(ans.encode('ascii')).decode('utf-8')}")
                    continue


    def send_my_input(self):
        with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as client:
            client.connect((self.host,int(self.server_port)))
            while True:
                response = client.recv(1024).decode()
                print_to_server(response)
                data = input()
                send_msg(client,data)
                print_to_client(data)





def main(argv):
    if len(argv) < 2:
        exit(1)
    Client(argv[1])


if __name__ == '__main__':
    main(sys.argv)
